/* *****************************************************************************************************************************
 * (c) J@mBeL.net 2010-2015
 * Author: John Ambeliotis
 * Created: 24 Apr. 2010
 *
 * License:
 *  This file is part of Project jaNET.

    Project jaNET is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Project jaNET is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with Project jaNET. If not, see <http://www.gnu.org/licenses/>. */

using System;
using System.Threading.Tasks;
using System.Xml;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
using System.IO;

namespace libJanet
{
    public static class Application
    {
        public static void Initialize()
        {
            string AppPath = Methods.getApplicationPath();
            ApplicationSettings appset = new ApplicationSettings();

            if (!File.Exists(AppPath + "AppConfig.xml"))
            {
                FileSystem.Log.Append("obj [ Global.Application.Initialize <AppConfig.xml> ]: File not found.");
                return;
            }
            if (!File.Exists(AppPath + ".htaccess"))
                new FileSystem.Settings().SaveSettings(".htaccess", "admin\r\nadmin");

            Methods.ToValues("%checkin%");
            Schedule.Init();
            if (!String.IsNullOrEmpty(appset.HostName))
                Server.Web.Start();
            if (!String.IsNullOrEmpty(appset.LocalHost))
                Server.TCP.Start();
            if (!String.IsNullOrEmpty(appset.ComPort))
                Listeners.ActivateSerialPort(string.Empty); // throws exception in linux?
        }

        public static void Dispose()
        {
            Listeners.DeactivateSerialPort();
            Server.Web.Stop();
            Server.TCP.Stop();
            Parser.ParserState = false;
            Environment.Exit(0);
        }
    }

    static class User
    {
        internal static volatile bool Status;
    }

    static class Process
    {
        internal static string Start(string sFilePath)
        {
            if (sFilePath.Trim().Contains(" "))
            {
                String fileName = sFilePath.Substring(0, sFilePath.IndexOf(' '));
                String arguments = sFilePath.Substring(fileName.Length);
                return Start(fileName, arguments);
            }
            else
                return Start(sFilePath, string.Empty);
        }

        internal static string Start(string sFilePath, string sArguments)
        {
            try
            {
                if (sFilePath != string.Empty)
                {
                    System.Diagnostics.Process process = new System.Diagnostics.Process();
                    process.EnableRaisingEvents = false;
                    
                    if (sArguments != string.Empty)
                    {
                        process.StartInfo.FileName = sFilePath;
                        process.StartInfo.Arguments = sArguments;
                    }
                    else
                        process.StartInfo.FileName = sFilePath;

                    process.StartInfo.UseShellExecute = false;
                    process.StartInfo.RedirectStandardOutput = true;
                    process.StartInfo.CreateNoWindow = true;
                    process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
                    process.Start();
                    string output = process.StandardOutput.ReadToEnd();
                    process.WaitForExit();
                    process.Close();
                    
                    return output;
                }
                return string.Empty;
            }
            catch (Exception e)
            {
                FileSystem.Log.Append("obj [ Process.Start <Exception> ]: args [ " + sFilePath + " " + sArguments + " ]: " + e.Message);
                return string.Empty;
            }
        }
		
        // True => worked, False => timeout
        internal static bool CallWithTimeout(Action method, int timeout)
        {
            Exception e;
            Task worker = Task.Factory.StartNew(method)
                              .ContinueWith(t =>
                              {
                                  // Ensure any exception is observed, is no-op if no exception.
                                  // Using closure to help avoid this being optimised out.
                                  e = t.Exception;
                              });
            return worker.Wait(timeout);
        }
    }
	
    class InstructionSet
    {
        internal string Id { get; set; }
        internal string Action { get; set; }
        internal string Category { get; set; }
        internal string Header { get; set; }
        internal string ShortDescription { get; set; }
        internal string Description { get; set; }
        internal string ThumbnailUrl { get; set; }
        internal string RealTime { get; set; }

        internal InstructionSet()
        {
            //
        }

        internal InstructionSet(string action)
        {
            this.Action = action;
        }

        internal InstructionSet(string id, string action)
        {
            this.Id = id;
            this.Action = action;
        }

        internal InstructionSet(string id, string action, string category, string header, string shortDescription, string description, string thumbnailUrl, string realTime)
        {
            this.Id = id;
            this.Action = action;

            if (!String.IsNullOrEmpty(category))
                this.Category = category;
            if (!String.IsNullOrEmpty(header))
                this.Header = header;
            if (!String.IsNullOrEmpty(shortDescription))
                this.ShortDescription = shortDescription;
            if (!String.IsNullOrEmpty(description))
                this.Description = description;
            if (!String.IsNullOrEmpty(thumbnailUrl))
                this.ThumbnailUrl = thumbnailUrl;
            if (!String.IsNullOrEmpty(realTime))
                this.RealTime = realTime;
        }
    }

    #region Weather
    class Weather
    {
        internal string TodayConditions { get; private set; }
        internal string TodayLow { get; private set; }
        internal string TodayHigh { get; private set; }
        internal string TodayDay { get; private set; }
        internal string TomorrowConditions { get; private set; }
        internal string TomorrowLow { get; private set; }
        internal string TomorrowHigh { get; private set; }
        internal string TomorrowDay { get; private set; }

        internal Weather()
        {
            Action getWeather = () => {
                try
                {
                    string endpoint = Queries.Xml.AppConfigQuery("jaNET/System/Others/YahooForecastFeed").Item(0).InnerText;
                    string ns = "yweather";
                    string uri = "http://xml.weather.yahoo.com/ns/rss/1.0";
                    string nodePath = "/rss/channel/item/yweather:forecast";

                    XmlNodeList nodes = Queries.Xml.SelectNodeList(endpoint, ns, uri, nodePath);
                    List<String> le = new List<String>();

                    foreach (XmlNode node in nodes)
                    {
                        le.Add(GetDay(node.Attributes["day"].InnerText));
                        le.Add(node.Attributes["text"].InnerText);
                        le.Add(node.Attributes["low"].InnerText);
                        le.Add(node.Attributes["high"].InnerText);
                    }
                    //Today conditions
                    TodayDay = le[0];
                    TodayConditions = le[1].Replace("/", ", ");
                    TodayLow = le[2];
                    TodayHigh = le[3];
                    //Tomorrow conditions
                    TomorrowDay = le[4];
                    TomorrowConditions = le[5].Replace("/", ", ");
                    TomorrowLow = le[6];
                    TomorrowHigh = le[7];
                }
                catch {
                    // Suppress
                }
            };
            Process.CallWithTimeout(getWeather, 10000);
        }

        private static string GetDay(string sDay)
        {
            switch (sDay)
            {
                case "Sun":
                    return "Sunday";
                case "Mon":
                    return "Monday";
                case "Tue":
                    return "Tuesday";
                case "Wed":
                    return "Wednesday";
                case "Thu":
                    return "Thursday";
                case "Fri":
                    return "Friday";
                case "Sat":
                    return "Saturday";
            } return string.Empty;
        }
    }
    #endregion
}